﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace JGTM.WPF.ActiveDataObject
{
    public static class ActiveObjectServices
    {
        /// <summary>
        /// Make a property alive notifying of value changes at given update interval.
        /// </summary>
        /// <typeparam name="T">Type which contains specified property.</typeparam>
        /// <param name="propertyName">Name of the property to make alive.</param>
        /// <param name="updateInterval">Time interval for property to notify its value changes.</param>
        public static void MakeAlive<T>(string propertyName, TimeSpan updateInterval)
        {
            PropertyInfo property = typeof(T).GetProperty(propertyName);

            if (property == null)
                throw new Exception(String.Format("Property doesn't exist: {0}.{1}", typeof(T), propertyName));

            MakeAlive(property, updateInterval);
        }

        /// <summary>
        /// Make a property alive notifying of value changes at given update interval.
        /// </summary>
        /// <param name="property">Property to make alive.</param>
        /// <param name="updateInterval">Time interval for the property to notify its value changes.</param>
        public static void MakeAlive(this PropertyInfo property, TimeSpan updateInterval)
        {
            ActiveDataObjectService.Register(new ActivePropertyRegistration()
            {
                HostType = property.DeclaringType,
                Property = new IntervalActivePropertyDescriptor(property, updateInterval)
            });
        }

        /// <summary>
        /// Make a property alive notifying of value changes when a trigger event fires.
        /// </summary>
        /// <typeparam name="T">Type which contains specified property.</typeparam>
        /// <param name="propertyName">Name of the property to make alive.</param>
        /// <param name="triggerEventName">Name of the trigger event for notifying property value changes.</param>
        public static void MakeAlive<T>(string propertyName, string triggerEventName)
        {
            PropertyInfo property = typeof(T).GetProperty(propertyName);

            if (property == null)
                throw new Exception(String.Format("Property doesn't exist: {0}.{1}", typeof(T), propertyName));

            EventInfo triggerEvent = typeof(T).GetEvent(triggerEventName);

            if (triggerEvent == null)
                throw new Exception(String.Format("Event doesn't exist: {0}.{1}", typeof(T), triggerEventName));

            MakeAlive(property, triggerEvent);
        }

        /// <summary>
        /// Make a property alive notifying of value changes when a trigger event fires.
        /// </summary>
        /// <param name="property">Property to make alive.</param>
        /// <param name="triggerEvent">Trigger event for notifying property value changes.</param>
        public static void MakeAlive(this PropertyInfo property, EventInfo triggerEvent)
        {
            ActiveDataObjectService.Register(new ActivePropertyRegistration()
            {
                HostType = property.DeclaringType,
                Property = new TriggerEventPropertyDescriptor(property, triggerEvent)
            });
        }

        /// <summary>
        /// Promote an event args to an active property which notifys value changes when the event is occuring.
        /// </summary>
        /// <typeparam name="PropT">Type of created property, must be same as the event args type for now.</typeparam>
        /// <param name="objectType">Type where event and new property live.</param>
        /// <param name="propertyName">Name of created property.</param>
        /// <param name="triggerEventName">Name of trigger event.</param>
        public static void CreateEventArgsProperty<PropT>(this Type objectType, string propertyName, string triggerEventName)
        {
            EventInfo triggerEventInfo = objectType.GetEvent(triggerEventName);

            if (triggerEventName == null)
                throw new Exception(String.Format("Event doesn't exist: {0}.{1}", objectType, triggerEventName));

            ActiveDataObjectService.Register(new ActivePropertyRegistration()
            {
                HostType = objectType,
                Property = new TriggerEventArgsPropertyDescriptor<PropT>(propertyName, triggerEventInfo)
            });
        }

        /// <summary>
        /// Promote an event args to an active property which notifys value changes when the event is occuring.
        /// </summary>
        /// <typeparam name="PropT">Type of created property, must be same as the event args type for now.</typeparam>
        /// <param name="objectType">Type where event and new property live.</param>
        /// <param name="propertyName">Name of created property.</param>
        /// <param name="triggerEventName">Trigger event.</param>
        public static void CreateEventArgsProperty<PropT>(this Type objectType, string propertyName, EventInfo triggerEvent)
        {
            ActiveDataObjectService.Register(new ActivePropertyRegistration()
            {
                HostType = objectType,
                Property = new TriggerEventArgsPropertyDescriptor<PropT>(propertyName, triggerEvent)
            });
        }
    }
}
